package com.bgs.engineering.util;


import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 使用hutool导出excel
 *
 * @author wh
 * @date 2023年7月31日10:51:42
 */
@Slf4j
public class HutoolExportExcelUtil {

  /**
   * 使用hutool导出excel
   *
   * @param response    响应
   * @param clazz       对象
   * @param list        实际要导出的数据
   * @param fileName    文件名称
   * @param sheetName   sheet名
   * @param removeField 需要过滤的字段
   * @throws Exception
   */
  public static void export(HttpServletResponse response, Class clazz, List<?> list, String fileName, String sheetName, String[] removeField) throws Exception {
    if (!list.isEmpty()) {
      if (!list.get(0).getClass().equals(clazz)) {
        log.error("数据类型与传入的集合数据类型不一致！数据类型：{}; 集合数据类型：{}", clazz, list.get(0).getClass());
        throw new Exception("数据类型与传入的集合数据类型不一致！");
      } else {
        ExcelWriter writer = ExcelUtil.getWriter();
        // 获取当前类字段
        Field[] fields = clazz.getDeclaredFields();
        // 字段名称集合
        List<String> fieldNames = new ArrayList<>();
        // 字段中文名称集合（获取实体中@ApiModelProperty注解value的值）
        List<String> cnNames = new ArrayList<>();
        for (Field field : fields) {
          if (!field.isAccessible()) {
            // 关闭反射访问安全检查，为了提高速度
            field.setAccessible(true);
          }
          String fieldName = field.getName();
          // 排除ID和序号,如果不需要过滤字段直接将字段添加即可
          if (!(Arrays.asList(removeField).contains(fieldName))) {
            fieldNames.add(fieldName);
          }
          // 判断是否有@ApiModelProperty注解
          boolean annotationPresent = field.isAnnotationPresent(ApiModelProperty.class);
          if (!(Arrays.asList(removeField).contains(fieldName)) && annotationPresent) {
            ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
            String name = annotation.value();
            cnNames.add(name);
          }
        }
        String[] fs = fieldNames.toArray(new String[0]);
        String[] ns = cnNames.toArray(new String[0]);
        for (int i = 0; i < ns.length; i++) {
          // 设置表头及字段名
          writer.addHeaderAlias(fs[i], ns[i]);
        }
        // 自动换行
        Workbook workbook = writer.getWorkbook();
        StyleSet styleSet = new StyleSet(workbook);
        styleSet.setWrapText();
        writer.setStyleSet(styleSet);
        // 确保只导出带有别名的字段
        writer.setOnlyAlias(true);
        //使用hutool时导出会自动带一个空的sheet1，需要将sheet重命名
        writer.renameSheet(sheetName);
        //增加标题，第一行整体合并为一个单元格
        writer.merge(fs.length - 1, sheetName);
        //单独设置第一行的高度
        writer.setRowHeight(0, 40);
        //开始写数据
        writer.write(list, true);

        ServletOutputStream out = response.getOutputStream();
        try {
          for (int i = 0; i < fieldNames.size(); i++) {
            writer.setColumnWidth(i, 23);
          }
//          //数据都写完之后，根据需求合并第一列的某些行，下标从0开始,合并列必须在所有行数据写完之后操作
//          writer.merge(2, 6, 0, 0, "路网", false);
//          writer.merge(7, list.size(), 0, 0, "赣岳", false);
          //
          response.setContentType("application/x-msdownload;charset=utf-8");
//          String ecodeFileName = URLEncoder.encode(fileName, "UTF-8");
          // 设置响应头，控制浏览器下载该文件
          //
          response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");


          writer.flush(out, true);
          writer.close();
          IoUtil.close(out);
        } catch (IOException e) {
          log.error(e.getMessage());
          e.printStackTrace();
        }
      }
    } else {
      log.error("数据集合为空");
      throw new Exception("数据集合为空");
    }
  }
}
